﻿#include "board.h"
#include <QPainter>
#include <QResource>
#include <QIcon>
#include <QDebug>
#include <QPicture>

#define ROW_LINE_COUNT 10   // 棋盘横线数
#define COL_LINE_COUNT 9    // 棋盘竖线数
#define STONE_DIAMETER 56   // 棋子直径
#define LABEL_DIAMETER 44   // 标签直径

#define ORIGIN_X 36         // 棋盘x起点
#define ORIGIN_Y 36         // 棋盘y起点

#define CHESS_RES_PATH "./chess.rcc"    // 资源文件所在目录
#define BOARD_ID 14         // 棋盘图片资源所在的ID
#define MASK_ID 15          // 提示走棋步骤
#define MASK2_ID 16         // 提示走棋步骤

#define CHESS_TITLE "中国象棋1.0"
#define WIDTH 520           // 宽
#define HEIGHT 576          // 高

QString PicResource[] = {
    ":/ChessImage/br.ico", // 黑車
    ":/ChessImage/bn.ico", // 黑马
    ":/ChessImage/bb.ico", // 黑象
    ":/ChessImage/ba.ico", // 黑士
    ":/ChessImage/bk.ico", // 黑将
    ":/ChessImage/bc.ico", // 黑炮
    ":/ChessImage/bp.ico", // 黑卒

    ":/ChessImage/rr.ico", // 红車
    ":/ChessImage/rn.ico", // 红马
    ":/ChessImage/rb.ico", // 红相
    ":/ChessImage/ra.ico", // 红仕
    ":/ChessImage/rk.ico", // 红帅
    ":/ChessImage/rc.ico", // 红炮
    ":/ChessImage/rp.ico", // 红兵

    ":/ChessImage/BOARD.BMP", // 棋盘
    ":/ChessImage/mask.png",  // 走棋提示
    ":/ChessImage/mask2.png", // 走棋提示

    ":/ChessImage/ChessIcon.ico" // 程序图标
};

enum{
    B_CHE,
    B_MA,
    B_XIANG,
    B_SHI,
    B_JIANG,
    B_PAO,
    B_ZU,

    R_CHE,
    R_MA,
    R_XIANG,
    R_SHI,
    R_SHUAI,
    R_PAO,
    R_BING,

    BOARD,
    MASK,
    MASK2,

    CHESS
};

/**
 * @brief 32个棋子
 */
int idMapPic[] = {
    B_CHE,
    B_MA,
    B_XIANG,
    B_SHI,
    B_JIANG,
    B_SHI,
    B_XIANG,
    B_MA,
    B_CHE,

    B_PAO,
    B_PAO,

    B_ZU,
    B_ZU,
    B_ZU,
    B_ZU,
    B_ZU,

    R_CHE,
    R_MA,
    R_XIANG,
    R_SHI,
    R_SHUAI,
    R_SHI,
    R_XIANG,
    R_MA,
    R_CHE,

    R_PAO,
    R_PAO,

    R_BING,
    R_BING,
    R_BING,
    R_BING,
    R_BING,
};

Board::Board(QWidget *parent) : QWidget(parent)
{
    // 注册二进制资源信息
    // QResource::registerResource(CHESS_RES_PATH);
    m_board.load(PicResource[BOARD]);

    setFixedSize(WIDTH, HEIGHT);

    //设置窗口标题
    setWindowTitle(CHESS_TITLE);

    //设置窗口标题
    setWindowIcon(QIcon(PicResource[CHESS]));

    for (int i = 0; i < STONE_COUNT; i++)
    {
        _s[i].init(i);
    }

    _selectid = -1;
    _startPos.setX(-1);
    _startPos.setY(-1);
    _endPos.setX(-1);
    _endPos.setY(-1);
    _bRedTurn = true;
    _r = STONE_DIAMETER/2;
}

void Board::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    /**
     *  棋盘
     *  1、起始坐标点（36,36）
     *  2、棋格边长56
     *  3、右下角坐标点（484,540）
     */

    // 棋盘
    painter.drawPixmap(0, 0, m_board);

    // 绘制32个棋子
    for (int i = 0; i < STONE_COUNT; i++)
    {
        drawStone(painter, i);
    }

    // 走棋的起始位置


    if (-1 != _startPos.rx() && -1 != _startPos.ry())
    {
        painter.drawPixmap(_startPos, PicResource[MASK]);
    }

    // 走棋的结束位置
    if (-1 != _endPos.rx() && -1 != _endPos.ry())
    {
        painter.drawPixmap(_endPos, PicResource[MASK2]);
    }
}

void Board::mousePressEvent(QMouseEvent *)
{

}

void Board::mouseReleaseEvent(QMouseEvent *ev)
{
    QPoint pt = ev->pos();
    // 将pt转化成象棋的行列值，判断这个行列值上是否有棋子

    int i = 0;
    int row, col;
    bool bRet = getRowCol(pt, row, col); // 获取释放鼠标点的位置在棋盘的哪个行列上
    if (bRet == false)  // 点到棋盘外
        return;

    // 判断点中的棋子
    int clickid = -1;
    for(i = 0; i < STONE_COUNT; i++)
    {
        if (_s[i]._row == row && _s[i]._col == col && _s[i]._dead == false)
        {
            break;
        }
    }

    if (i < STONE_COUNT)
    {
         clickid = i;
    }

    // 选棋子
    if (_selectid == -1)
    {
        if(clickid != -1)
        {
            if (_bRedTurn == _s[clickid]._red) // 判断是否轮到走棋
            {
                // 选中棋子
                _selectid = clickid;

                QPoint c = center(clickid);
                c.setX(c.rx() - LABEL_DIAMETER/2);
                c.setY(c.ry() - LABEL_DIAMETER/2);
                _startPos = c;

                _endPos.setX(-1);
                _endPos.setY(-1);

                update();
            }
        }
    }
    // 走棋子
    else
    {
        if(canMove(_selectid, row, col, clickid))
        {
            /* 走棋代码 */
            _s[_selectid]._row = row;
            _s[_selectid]._col = col;
            if (clickid != -1)
            {
                _s[clickid]._dead = true; // 目标位置有对方棋，吃掉
            }
            _selectid = -1;

            QPoint c = center(row, col);
            c.setX(c.rx() - LABEL_DIAMETER/2);
            c.setY(c.ry() - LABEL_DIAMETER/2);
            _endPos = c;

            _bRedTurn = !_bRedTurn;
            update();
        }
    }
}

bool Board::getRowCol(QPoint pt, int &row, int &col)
{
    for (row = 0; row <= ROW_LINE_COUNT - 1; row++)
    {
        for (col = 0; col <= COL_LINE_COUNT - 1; col++)
        {
            QPoint c = center(row, col);
            int dx = c.x() - pt.x();
            int dy = c.y() - pt.y();
            int dist = dx*dx + dy*dy;
            if (dist < _r*_r)
                return true;
        }
    }
    return false;
}

bool Board::getRowCol(int id, int &row, int &col)
{
    if (id < 0 || id >= 32)
        return false;

    row = _s[id]._row;
    col = _s[id]._col;
    return true;
}

void Board::drawStone(QPainter& painter, int id)
{
    if(_s[id]._dead)
        return;

    QPoint c = center(id);
    c.setX(c.rx() - STONE_DIAMETER/2);
    c.setY(c.ry() - STONE_DIAMETER/2);

    painter.drawPixmap(c, QPixmap(PicResource[idMapPic[id]])); // 背景透明

}

int Board::relation(int row1, int col1, int row, int col)
{
    return qAbs(row1 - row)*10 + qAbs(col1 - col);
}

bool Board::isExistStone(int row, int col)
{
    for (int i = 0; i < STONE_COUNT; i++) {
        if (_s[i]._row == row && _s[i]._col == col && _s[i]._dead == false)
            return true;
    }
    return false;
}

bool Board::isBottomSide(int id)
{
    if (id < 0 || id >= STONE_COUNT)
        return false;

    if (id < STONE_COUNT/2)
        return false;

    return true;
}

int Board::getStoneCountAtLine(int row1, int col1, int row2, int col2)
{
    int ret = 0;
    if (row1 != row2 && col1 != col2)
        return -1;

    if (row1 == row2 && col1 == col2)
        return -1;

    if (row1 == row2)
    {
        int min = col1 < col2 ? col1 : col2;
        int max = col1 < col2 ? col2 : col1;
        for (int col = min + 1; col < max; ++col) {
            if (isExistStone(row1, col))
                ++ret;
        }
    }
    else
    {
        int min = row1 < row2 ? row1 : row2;
        int max = row1 < row2 ? row2 : row1;
        for (int row = min + 1; row < max; ++row) {
            if (isExistStone(row, col1))
                ++ret;
        }
    }

    return ret;
}

/**
 * @brief 判断这步棋是否符合规则
 */
bool Board::canMove(int moveid, int row, int col, int killid)
{
    if(_s[moveid]._red == _s[killid]._red) // moveid和killid颜色相同
    {
        // 换选择
        _selectid = killid;

        QPoint c = center(_selectid);
        c.setX(c.rx() - LABEL_DIAMETER/2);
        c.setY(c.ry() - LABEL_DIAMETER/2);
        _startPos = c;

        update();
        return false;
    }

    switch(_s[moveid]._type)
    {
        case Stone::JIANG:
            return canMoveJIANG(moveid, row, col);
            break;
        case Stone::SHI:
            return canMoveSHI(moveid, row, col);
            break;
        case Stone::XIANG:
            return canMoveXIANG(moveid, row, col);
            break;
        case Stone::CHE:
            return canMoveCHE(moveid, row, col);
            break;
        case Stone::MA:
            return canMoveMA(moveid, row, col);
            break;
        case Stone::PAO:
            return canMovePAO(moveid, row, col, killid);
            break;
        case Stone::BING:
            return canMoveBING(moveid, row, col);
            break;
        default:
            break;
    }
    return false;
}

/**
 * 将、帅
 */
bool Board::canMoveJIANG(int moveid, int row, int col)
{
    /*
        1.首先目标位置在九宫内
        2.移动的步长是一个格子
    */
    if (_s[moveid]._red)
    {
        if(row > 2)
            return false;
    }
    else
    {
        if(row < 7)
            return false;
    }

    if (col < 3)
        return false;

    if(col > 5)
        return false;

    int dr = _s[moveid]._row - row;
    int dc = _s[moveid]._col - col;
    int d = abs(dr)*10 + abs(dc);
    if(d == 1 || d == 10)
        return true;

    return false;
}

/**
 * 士
 */
bool Board::canMoveSHI(int moveid, int row, int col)
{    
    if (_s[moveid]._red)
    {
        if(row > 2)
            return false;
    }
    else
    {
        if(row < 7)
            return false;
    }

    if (col < 3)
        return false;

    if(col > 5)
        return false;

    int dr = _s[moveid]._row - row;
    int dc = _s[moveid]._col - col;
    int d = abs(dr)*10 + abs(dc);
    if(d == 11)
        return true;

    return false;
}

/**
 * 象、相
 */
bool Board::canMoveXIANG(int moveid, int row, int col)
{
    int row1 = -1;
    int col1 = -1;
    getRowCol(moveid, row1, col1);
    int r = relation(row1, col1, row, col);
    if (22 != r) // 相走田规则
        return false;

    // 田中间是否有棋，有则不能走
    int rEye = (row + row1)/2;
    int cEye = (col + col1)/2;
    if (isExistStone(rEye, cEye))
        return false;

    if (isBottomSide(moveid))
    {
        if (row < 4)
            return false;
    }
    else
    {
        if (row > 5)
            return false;
    }
    return true;
}

/**
 * 车
 */
bool Board::canMoveCHE(int moveid, int row, int col)
{
    int row1 = -1;
    int col1 = -1;
    getRowCol(moveid, row1, col1);
    int ret = getStoneCountAtLine(row1, col1, row, col);
    if (0 == ret)
        return true;

    return false;
}

/**
 * 马
 */
bool Board::canMoveMA(int moveid, int row, int col)
{
    int row1 = -1;
    int col1 = -1;
    getRowCol(moveid, row1, col1);
    int r = relation(row1, col1, row, col);
    if (r != 12 && r != 21)
        return false;

    if (12 == r)
    {
        if (isExistStone(row1, (col + col1)/2))
            return false;
    }
    else
    {
        if (isExistStone((row + row1)/2, col1))
            return false;
    }
    return true;
}

/**
 * 炮
 */
bool Board::canMovePAO(int moveid, int row, int col, int killid)
{
    int row1 = -1;
    int col1 = -1;
    getRowCol(moveid, row1, col1);
    int ret = getStoneCountAtLine(row, col, row1, col1);
    if (killid != -1)
    {
        if(1 == ret)
            return true;
    }
    else
    {
        if(0 == ret)
            return true;
    }
    return false;
}

/**
 * 兵、卒
 */
bool Board::canMoveBING(int moveid, int row, int col)
{
    int row1 = -1;
    int col1 = -1;
    getRowCol(moveid, row1, col1);
    int r = relation(row1, col1, row, col);
    if (r != 1 && r != 10)
        return false;

    if (isBottomSide(moveid))
    {
        if (row > row1)
            return false;

        if (row1 >= 5 && row == row1)
            return false;
    }
    else
    {
        if (row < row1)
            return false;

        if (row1 <= 4 && row == row1)
            return false;
    }
    return true;
}

QPoint Board::center(int row, int col)
{
      QPoint ret;
      ret.setX(col*STONE_DIAMETER + ORIGIN_X);
      ret.setY(row*STONE_DIAMETER + ORIGIN_Y);
      return ret;
}

QPoint Board::center(int id)
{
    return center(_s[id]._row, _s[id]._col);
}
